#ifndef HIKVISION_IR_CAMERA_HPP
#define HIKVISION_IR_CAMERA_HPP

#include <string>
#include <thread>
#include <atomic>
#include <mutex>
#include <queue>
#include <vector>
#include <condition_variable>
#include <semaphore>

#ifdef __cplusplus
extern "C" {
#endif

#include "HCNetSDK.h"

#ifdef __cplusplus
}
#endif

typedef struct
{
	short year;             /*APP->DSP 年*/
	short month;            /*APP->DSP 月*/
	short dayOfWeek;        /*APP->DSP 0:星期日-6:星期六*/
	short day;              /*APP->DSP 日*/
	short hour;             /*APP->DSP 小时*/
	short minute;           /*APP->DSP 分钟*/
	short second;           /*APP->DSP 秒*/
	short milliSecond;      /*APP->DSP 毫秒*/
}DATE_TIME;

typedef struct
{
	UINT u32TmDataMode;      /* 0为4字节，1为2字节 */
	UINT u32TmScale;         /* 测温缩放比例 */
	UINT u32TmOffset;        /* 测温偏移量，当前固定为0 */
	LONG  byIsFreezedata;    /*是否是冻结数据，1:冻结，0:非冻结*/
}STREAM_FS_SUPPLE_INFO_TEMP;

typedef struct _STREAM_RT_DATA_INFO_S_
{
	UINT u32RTDataType; 	// 1-14bit裸数据; 2-全屏测温结果数据; 3-YUV数据
	UINT u32FrmNum;
	UINT u32StdStamp; 		// DSP相对时间戳
	DATE_TIME stTime; 		// 绝对时间戳
	UINT u32Width;
	UINT u32Height;
	UINT u32Len;
	UINT u32Fps;
	UINT u32Chan;
}STREAM_RT_DATA_INFO_S;

typedef struct _STREAM_FARME_INFO_TEMP_S_
{
	UINT u32MagicNo;        // 0x70827773  "FRMI"的ascll码
	UINT u32HeaderSize;     // 结构体长度
	UINT u32StreamType;     // 数据类型： h264/h265, JPEG, Audio, MetaData, RTData: 参见 STREAM_TYPE_E
	UINT u32StreamLen;      // 数据长度
	STREAM_RT_DATA_INFO_S stRTDataInfo;
	STREAM_FS_SUPPLE_INFO_TEMP stFsSuppleInfo;
	UINT res[12];
	UINT u32CrcVal; 		// 结构体校验码 对结构体前面数据进行校验
}STREAM_FARME_INFO_TEMP;

typedef struct raw_data_handle_t
{	
	uint8_t *frame_buffer;                           			// 裸数据
	std::mutex frame_buffer_mutex;                   			// 裸数据互斥锁
	size_t frame_data_start_index;                    			// 裸数据头地址
	size_t frame_data_end_index;                          		// 裸数据尾地址
	size_t buffer_size;                          				// 剩余内存大小

	const uint8_t MAGIC_BYTES[4] = {0x73, 0x77, 0x82, 0x70};	// 魔术字
	size_t magic_byte_start_index;                    			// 第一个魔术字的地址
	size_t magic_byte_end_index;                          		// 第二个魔术字的地址
	int  magic_byte_found_cout;									// 魔术字找到的次数
	
	std::counting_semaphore<10> frame_sem{0};      				// 帧可用信号量
	std::atomic<bool> running_;                    				// 线程运行标志
    std::thread frame_processor_thread_;           				// 帧处理线程

	uint16_t max_frame_queue_size;                    			// 裸数据队列大小
	std::queue<std::vector<uint16_t>> frame_queue; 				// 裸数据队列
	std::mutex frame_queue_mutex;                  				// 裸数据队列互斥锁

	uint8_t* grey_8bit_image;									// 8位灰度图像
	uint16_t* grey_16bit_image;									// 16位灰度图像
	std::mutex grey_image_mutex;								// 8位灰度图像互斥锁
}raw_data_handle_t;

typedef struct camera_handle_t
{	
	LONG lUserID;           					// 用户ID句柄
	LONG lRealPlayHandle;						// 实时预览句柄
	std::thread connect_status_check_thread_;	// 网线连接状态检查线程
	std::atomic<bool> running_;                 // 线程运行标志
	bool is_connected;							// 是否连接
	NET_DVR_USER_LOGIN_INFO loginInfo; // 登录信息
    NET_DVR_DEVICEINFO_V40 deviceInfo; // 设备信息
}camera_handle_t;

class HikvisionIRCamera
{
public:
	HikvisionIRCamera();
	
	~HikvisionIRCamera();

	std::vector<uint16_t> get_grey_16bit_image(raw_data_handle_t* raw_data);

	std::vector<uint16_t> get_grey_8bit_image(raw_data_handle_t* raw_data);
private:
	#define CAMERA_WIDTH 384
	#define CAMERA_HEIGHT 288
	#define PIXEL_SIZE 2
	#define CACHE_FRAME_NUM 25
	#define BUFFER_SIZE (CAMERA_WIDTH * CAMERA_HEIGHT * PIXEL_SIZE * CACHE_FRAME_NUM)
	#define MAX_FRAME_QUEUE_SIZE CACHE_FRAME_NUM
	
	raw_data_handle_t raw_data;		   // 图像数据队列
	camera_handle_t camera_handle; // 摄像头句柄

	void init_camera_handle_t(camera_handle_t* camera_handle);

	void init_raw_data_t(raw_data_handle_t* raw_data);

	void release_memery(camera_handle_t* camera_handle, raw_data_handle_t* raw_data);

	bool is_connect(const std::string& ipAddress, int port, int timeoutSec);

	void check_login_status_thread_function(camera_handle_t* camera_handle, raw_data_handle_t* raw_data);

	static void CALLBACK g_RealDataCallBack_V30(LONG lRealHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, void* pUser);

	void write_to_buffer(raw_data_handle_t* raw_data, BYTE *pBuffer, DWORD dwBufSize);

	int find_magic_from_buffer(raw_data_handle_t* raw_data);

	void start_get_raw_data(camera_handle_t* camera_handle, raw_data_handle_t* raw_data);

	void stop_get_raw_data(camera_handle_t* camera_handle);

	void start_check_login_status_thread(camera_handle_t* camera_handle);

	void stop_check_login_status_thread(camera_handle_t* camera_handle);

	int raw_data_to_grey_16bit(raw_data_handle_t* raw_data, size_t start_pos, size_t end_pos);

	void frame_processor_thread_function(raw_data_handle_t* raw_data);

	void start_frame_processor_thread(raw_data_handle_t* raw_data);

	void stop_frame_processor_thread(raw_data_handle_t* raw_data);

	int get_grey_16bit_from_queue(raw_data_handle_t* raw_data, std::vector<uint16_t>& frame);

	int get_grey_16bit_image(raw_data_handle_t* raw_data, std::vector<uint16_t>& frame);

	int get_grey_8bit_image(raw_data_handle_t* raw_data, std::vector<uint8_t>& frame);
};

#endif